import sys
import math
import random
import numpy as np
from PyQt5.QtCore import Qt, QTimer, QRectF, QPointF, QSize
from PyQt5.QtGui import (QImage, QPainter, QPainterPath, QLinearGradient,
                         QColor, QTransform, QBrush, QPen)
from PyQt5.QtWidgets import QApplication, QWidget, QGraphicsBlurEffect

class PhysicsWaveEffect(QWidget):
    def __init__(self, img_path):
        super().__init__()
        self.original_img = QImage(img_path)
        if self.original_img.isNull():
            raise ValueError("无法加载图像文件")
        
        # 物理参数系统
        self.wave_params = {
            'amplitude': 15,       # 主波振幅 [1](@ref)
            'secondary_ratio': 0.6,# 次级波比例 [3](@ref)
            'frequency': 0.16,     # 波纹密度 [1,3](@ref)
            'speed': 0.18,         # 波动速度 [3](@ref)
            'noise_strength': 4,   # 噪声强度 [1](@ref)
            'refract_offset': 5    # 折射偏移量 [3](@ref)
        }
        
        # 光学参数系统
        self.optical_params = {
            'reflection_opacity': 0.82,  # 初始透明度 [2](@ref)
            'highlight_strength': 120,  # 高光强度 [2](@ref)
            'blur_radius': 8,           # 模糊半径 [3](@ref)
            'gradient_curve': [         # 渐变曲线 [1](@ref)
                (0.0, 0.85),
                (0.6, 0.4),
                (1.0, 0.0)
            ]
        }
        
        self.init_ui()
        self.init_wave_engine()

    def init_ui(self):
        self.setWindowTitle("物理级水波倒影系统")
        self.setFixedSize(self.original_img.width(), 
                         self.original_img.height() * 1.8)
        
        # 生成倒影图像
        self.reflection_img = self.create_reflection_image()
        
        # 初始化波浪场
        self.wave_phase = 0.0
        self.wave_sources = []  # 互动涟漪存储
        
        # 渲染定时器
        self.render_timer = QTimer(self)
        self.render_timer.timeout.connect(self.update_physics)
        self.render_timer.start(30)  # 33fps

    def create_reflection_image(self):
        """创建带光学特性的倒影图像[1,2](@ref)"""
        reflection = self.original_img.mirrored(False, True)
        
        # 应用渐变蒙版
        grad = QLinearGradient(0, 0, 0, reflection.height())
        for pos, alpha in self.optical_params['gradient_curve']:
            grad.setColorAt(pos, QColor(255,255,255, int(255*alpha)))
            
        painter = QPainter(reflection)
        painter.setCompositionMode(QPainter.CompositionMode_Darken)
        painter.fillRect(reflection.rect(), grad)
        
        # 添加动态模糊 [3](@ref)
        blur_effect = QGraphicsBlurEffect()
        blur_effect.setBlurRadius(self.optical_params['blur_radius'])
        reflection = reflection.applyEffect(blur_effect)
        
        painter.end()
        return reflection

    def init_wave_engine(self):
        """初始化物理波动引擎[1](@ref)"""
        self.wave_buffer = np.zeros((self.width(), 3), dtype=np.float32)
        
    def update_physics(self):
        """更新物理场状态[1,3](@ref)"""
        # 基础相位更新
        self.wave_phase += self.wave_params['speed']
        
        # 随机扰动
        self.wave_phase += random.uniform(-0.03, 0.03)
        
        # 互动涟漪衰减
        for wave in self.wave_sources:
            wave['radius'] += 2
            if wave['radius'] > wave['max_radius']:
                self.wave_sources.remove(wave)
        
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
        
        # 绘制原始图像
        painter.drawImage(0, 0, self.original_img)
        
        # 绘制动态倒影
        self.draw_physics_reflection(painter)

    def draw_physics_reflection(self, painter):
        """物理级倒影渲染[1,3](@ref)"""
        img_h = self.original_img.height()
        rect = QRectF(0, img_h, self.width(), img_h * 0.75)
        
        # 生成复合波形路径
        wave_path = self.generate_complex_wave(rect)
        
        # 设置折射变换
        transform = QTransform()
        transform.translate(
            self.wave_params['refract_offset'] * math.sin(self.wave_phase * 0.7),
            self.wave_params['refract_offset'] * math.cos(self.wave_phase * 0.5)
        )
        painter.setTransform(transform)
        
        # 裁剪波浪区域
        painter.setClipPath(wave_path)
        painter.drawImage(rect, self.reflection_img)
        
        # 绘制高光特效 [2](@ref)
        self.draw_optical_highlight(painter, rect)

    def generate_complex_wave(self, rect):
        """生成复合波形路径[1,3](@ref)"""
        path = QPainterPath()
        path.moveTo(rect.left()-10, rect.top())
        
        A = self.wave_params['amplitude']
        w = self.wave_params['frequency']
        phase = self.wave_phase
        
        for x in range(int(rect.left()-10), int(rect.right()+10)):
            # 主波方程
            y1 = A * math.sin(w * x + phase)
            
            # 次级波方程 [3](@ref)
            y2 = self.wave_params['secondary_ratio'] * A * math.cos(2*w*x + 1.5*phase)
            
            # 噪声波 [1](@ref)
            y3 = random.uniform(-self.wave_params['noise_strength'], 
                               self.wave_params['noise_strength'])
            
            # 互动涟漪叠加
            for wave in self.wave_sources:
                dx = x - wave['x']
                dy = math.sqrt(dx**2 + (rect.top() - wave['y'])**2)
                if dy < wave['radius']:
                    y3 += 3 * math.sin(dy * 0.1 - wave['radius'] * 0.3)
            
            total_y = y1 + y2 + y3
            path.lineTo(x, rect.top() + total_y)
        
        path.lineTo(rect.right()+10, rect.bottom())
        path.lineTo(rect.left()-10, rect.bottom())
        return path

    def draw_optical_highlight(self, painter, rect):
        """光学高光渲染[2,3](@ref)"""
        # 主高光层
        highlight1 = QLinearGradient(rect.topLeft(), rect.bottomLeft())
        highlight1.setColorAt(0.2, QColor(255,255,255,self.optical_params['highlight_strength']))
        highlight1.setColorAt(0.7, Qt.transparent)
        
        # 次高光层
        highlight2 = QRadialGradient(
            QPointF(rect.center().x(), rect.top() + 20), 
            rect.width() * 0.6
        )
        highlight2.setColorAt(0.4, QColor(200,230,255,80))
        highlight2.setColorAt(1.0, Qt.transparent)
        
        painter.setPen(Qt.NoPen)
        painter.setBrush(QBrush(highlight1))
        painter.drawRect(rect)
        painter.setBrush(QBrush(highlight2))
        painter.drawRect(rect)

    def mousePressEvent(self, event):
        """鼠标交互生成涟漪[3](@ref)"""
        self.wave_sources.append({
            'x': event.x(),
            'y': event.y(),
            'radius': 0,
            'max_radius': 100
        })

if __name__ == "__main__":
    app = QApplication(sys.argv)
    
    # 加载示例图片（替换为实际路径）
    try:
        window = PhysicsWaveEffect("../img/beauty02.png")
        window.show()
    except ValueError as e:
        print(str(e))
        sys.exit(1)
    
    sys.exit(app.exec_())